#include "device/air780e/AtNetworkHttpAir780E.h"

#define HTTP_BASE_CONFIG_0 "AT+HTTPINIT"           // 配置请求参数
#define HTTP_BASE_CONFIG_1 "AT+HTTPSSL=1"          // 配置请求参数
#define HTTP_BASE_CONFIG_2 "AT+HTTPPARA=\"CID\",1" // 配置请求参数

#define HTTP_BASE_SEND_URL "AT+HTTPPARA=\"URL\",\"%s\"\r\n" // 发送URL

#define HTTP_BASE_CLOSE "AT+HTTPTERM"        // HTTP请求已完成，释放相关资源
#define HTTP_BASE_READY "+HTTPACTION: 0,200" // HTTP请求已完成，待读取响应内容
#define HTTP_BASE_READ_CMD "AT+HTTPREAD"     // HTTP请求完成，开始读取响应内容
#define HTTP_BASE_READ_RES "+HTTPREAD: "     // HTTP响应已就绪，返回数据长度并开始接收

#define HTTP_GET_START_REQ "AT+HTTPACTION=0" // 发起GET请求

#define HTTP_POST_DATA_CMD "AT+HTTPDATA=%d,80000\r\n" // 发送请求数据
#define HTTP_POST_DATA_RES "DOWNLOAD\r\n"             // 发送请求数据，状态就绪
#define HTTP_POST_START_REQ "AT+HTTPACTION=1"         // 发起POST请求

/**
 * 发起GET请求
 */
size_t AtNetworkHttpAir780E::get(HttpCallback fun, char *url, uint32_t timeout) {
  if (fun != nullptr && this->executeRequest(fun, url) == AT_RCODE1) {
    this->device->streamWriteClear(HTTP_GET_START_REQ GSM_NL);
    if (this->wait(80000, HTTP_BASE_READY) == AT_RCODE1) {
      return this->executeResponse(fun, url);
    }
  }

  // -------------------------------------------------------------------
  // 释放HTTP资源
  // -------------------------------------------------------------------
  this->device->streamWriteClear(HTTP_BASE_CLOSE GSM_NL);
  this->device->streamReleaseInvalidLegacyData();

  return CONNECT_ERR_0;
}

/**
 * 发起POST请求
 */
size_t AtNetworkHttpAir780E::post(HttpCallback fun, char *url, char *body, uint32_t timeout) {
  if (fun != nullptr && this->executeRequest(fun, url) == AT_RCODE1) {
    this->device->streamPrintfClear(HTTP_POST_DATA_CMD, strlen(body));
    if (this->wait(5000, HTTP_POST_DATA_RES) == AT_RCODE1) {
      this->device->streamWriteClear(body, GSM_NL);
    } else {
      goto http_exit;
    }

    // 打开POST请求连接
    this->device->streamWriteClear(HTTP_POST_START_REQ GSM_NL);
    if (this->wait(80000, HTTP_BASE_READY) == AT_RCODE1) {
      return this->executeResponse(fun, url);
    }
  }

http_exit:
  // -------------------------------------------------------------------
  // 释放HTTP资源
  // -------------------------------------------------------------------
  this->device->streamWriteClear(HTTP_BASE_CLOSE GSM_NL);
  this->device->streamReleaseInvalidLegacyData();

  return CONNECT_ERR_0;
}

size_t AtNetworkHttpAir780E::executeResponse(HttpCallback fun, char *url) {
  // -------------------------------------------------------------------
  // 发送读取响应内容指令
  // -------------------------------------------------------------------
  this->device->streamWriteClear(HTTP_BASE_READ_CMD GSM_NL);
  if (this->wait(5000, HTTP_BASE_READ_RES) != AT_RCODE1) {
    return CONNECT_ERR_0;
  }

  // -------------------------------------------------------------------
  // 读取全部响应内容
  // -------------------------------------------------------------------
  size_t contentLength = this->device->streamGetInt(16, '\n');
  char *contentBody = (char *)MEM_ALLOC(contentLength + 1);
  for (size_t idx = 0; idx < contentLength; idx++) {
    while (!this->device->_stream->available()) {
      AT_YIELD();
    }

    contentBody[idx] = this->device->_stream->read();
    contentBody[idx + 1] = '\0';

    AT_YIELD();
  }

  // -------------------------------------------------------------------
  // 释放HTTP资源
  // -------------------------------------------------------------------
  this->device->streamWriteClear(HTTP_BASE_CLOSE GSM_NL);
  this->device->streamReleaseInvalidLegacyData();

  // -------------------------------------------------------------------
  // 响应内容回调
  // -------------------------------------------------------------------
  size_t res = fun(contentLength, contentBody);

  free(contentBody);

  return res;
}

size_t AtNetworkHttpAir780E::executeRequest(HttpCallback fun, char *url) {
  this->device->streamWriteClear(HTTP_BASE_CONFIG_0 GSM_NL);
  this->device->streamWriteClear(HTTP_BASE_CONFIG_1 GSM_NL);
  this->device->streamWriteClear(HTTP_BASE_CONFIG_2 GSM_NL);

  // -------------------------------------------------------------------
  // 发送HTTP请求的URL
  // -------------------------------------------------------------------
  this->device->streamPrintfClear(HTTP_BASE_SEND_URL, url);
  if (this->wait(5000, AT_OK) == AT_RCODE1) {
    return AT_RCODE1;
  }

  return CONNECT_ERR_0;
}
